#pragma once
#include <vector>
#include <string>
#include <algorithm> //copy

/**
 * @brief 网络库底层缓冲区 vector<char>
 * ---------------------------------------------
 *          |     readable   |        writeable
 * ---------------------------------------------
 * 0    readerIndex      writeIndex             size
 */
class Buffer {
    public:
        static const size_t kCheapPrepend = 8;
        static const size_t kInitialSize = 1024;

        explicit Buffer(size_t initialSize = kInitialSize)
            : buffer_(kCheapPrepend + initialSize),
              readerIndex_(kCheapPrepend),
              writerIndex_(kCheapPrepend)
        {}

        size_t readableBytes() const { return writerIndex_ - readerIndex_; }
        size_t writableBytes() const { return buffer_.size() - writerIndex_; }
        size_t prependableBytes() const { return readerIndex_; }

        const char *peek() const { return begin() + readerIndex_; } //返回缓冲区中可读数据的起始地址

        // onMessage string <- Buffer
        void retrieve(size_t len) {
            //assert(len <= readableBytes())

            if (len < readableBytes()) { // 表示数据还没有读完,也可以表示写入n个数据

                readerIndex_ += len; // index向前记录这次读完后的位置

            } else { // len == readableBytes() 表示可读数据读完了
                retrieveAll();
            }
        }

        void retrieveAll() {
            // 可读数据已经没有了
            readerIndex_ = kCheapPrepend;
            writerIndex_ = kCheapPrepend;
        }

        // 把onMessage函数上报的Buffer数据转换为string类型的数据返回
        std::string retrieveAllAsString() {
            return retrieveAsString(readableBytes()); //参数：可读取数据的长度
        }

        std::string retrieveAsString(size_t len) {
            std::string result(peek(), len);

            retrieve(len); //数据已经读出， 需要对缓冲区进行复位操作

            return result;
        }



        // 确保能写入区间长度writableBytes() 能大于等于len长度的写入数据
        void ensureWritableBytes(size_t len) {
            if (writableBytes() < len) {    // 扩容
                makeSpace(len); // 扩容函数
            }
        }

        // 把【data， data + len】上数据添加到writeable缓冲区中
        void append(const char *data, size_t len) {
            ensureWritableBytes(len);
            std::copy(data, data + len, beginWrite());
            writerIndex_ += len;
        } 

        char *beginWrite() {
            return begin() + writerIndex_;
        }

        const char *beginWrite() const {
            return begin() + writerIndex_;
        }

        // 从fd上读数据
        ssize_t readFd(int fd, int* savedErrno);
        ssize_t writeFd(int fd, int* saveErrno);

    private:
    /**
     * @brief socket操作数据需要用到指针
     * 
     */
        /*先调用*运算符求得元素，再调用&求得地址 */
        char *begin() { return &*buffer_.begin(); }
        const char *begin() const { return &*buffer_.begin(); }

        //扩容函数
        void makeSpace(size_t len) {
            /*
                剩余的可写空间比len大
            */
           if (writableBytes() + prependableBytes() - kCheapPrepend < len) {
               buffer_.resize(writerIndex_ + len);
           }
           // else
           /*
                ---------------------------------------
                    | 空闲 |   readable   |   writeable   
                ---------------------------------------
                0      readerIndex_  writerIndex_    size
           */
           else // 把未读数据(readable)向前挪，剩余空间就够写了
           {
               size_t readable = readableBytes();
               std::copy(begin() + readerIndex_, begin() + writerIndex_, begin() + kCheapPrepend);
               readerIndex_ = kCheapPrepend;
               writerIndex_ = readerIndex_ + readable;
           }
        }

        std::vector<char> buffer_;
        size_t readerIndex_;
        size_t writerIndex_;
    
};